package craky.keeper;

import java.awt.Image;
import java.awt.SplashScreen;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FilenameFilter;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.TreeMap;

import javax.swing.ImageIcon;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.ToolTipManager;

import org.hibernate.criterion.Criterion;

import com.sun.awt.AWTUtilities;

import craky.componentc.JCMessageBox;
import craky.keeper.category.Category;
import craky.keeper.category.CategoryDAO;
import craky.keeper.skin.Skin;
import craky.keeper.user.User;
import craky.keeper.user.UserDAO;
import craky.keeper.user.UserInfoDialog;
import craky.keeper.util.KeeperUtil;
import craky.security.Checker;
import craky.security.Digest;
import craky.util.Config;
import craky.util.UIUtil;

public class KeeperApp {
	private Config config;
	private Config loginConfig;
	private MainFrame mainFrame;
	private LoginFrame loginFrame;
	private Map<String, Skin> skinMap;
	private Skin currentSkin;
	private Skin currentPreviewSkin;
	private Timer gcTimer;
	private List<String> loginHistory;
	private Map<String, Category> categoryMap;
	private User currentUser;
	private String bannerName;

	public KeeperApp() {
		this.config = new Config(KeeperConst.CONFIG_PATH);
		this.loginConfig = new Config(KeeperConst.LOGIN_CONFIG_PATH);
		this.loginHistory = new ArrayList<String>(10);
		this.categoryMap = new LinkedHashMap<String, Category>();
		initBannerName();

		if (!isRunning()) {
			load();
		} else {
			System.exit(0);
		}
	}

	private boolean isRunning() {
		String info = null;
		RandomAccessFile raf = null;
		try {
			raf = new RandomAccessFile(KeeperConst.DATA_DIR
					+ KeeperConst.FILE_SEP + "smallsql.master", "rwd");
			FileChannel channel = raf.getChannel();
			FileLock lock = channel.tryLock();

			if (lock == null) {
				info = "该程序已经在运行 ";
			} else {
				lock.release();
			}
		} catch (Exception e) {
			info = "崩溃了，哈哈 ";
			try {
				if (raf != null) {
					raf.close();
				}
			} catch (Exception ex) {
				ex.printStackTrace();
			}
		} finally {
			try {
				if (raf != null) {
					raf.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		if (info != null) {
			closeSplash();
			showMessageBeforeLogin("三号管家", info, false);
		}

		return info != null;
	}

	public void loadAllSkin() {
		this.skinMap = new TreeMap<String, Skin>();
		Skin defaultSkin = new Skin("默认皮肤");
		this.skinMap.put(defaultSkin.getName().toUpperCase(), defaultSkin);
		File skinRoot = new File(KeeperConst.SKIN_DIR);

		if ((skinRoot.exists()) && (skinRoot.isDirectory())) {
			File[] skinDirs = skinRoot.listFiles();

			int count = 0;

			for (File skinDir : skinDirs) {
				if (!skinDir.isDirectory())
					continue;
				String name = skinDir.getName();
				String path = skinDir.getPath();
				File file = new File(path + KeeperConst.FILE_SEP + "normal.png");

				if ((!file.exists()) || (!file.isFile())) {
					continue;
				}

				file = new File(path + KeeperConst.FILE_SEP + "blur.png");

				if ((!file.exists()) || (!file.isFile())) {
					continue;
				}

				file = new File(path + KeeperConst.FILE_SEP + "preview.png");

				if ((!file.exists()) || (!file.isFile())) {
					continue;
				}

				this.skinMap.put(name.toUpperCase(), new Skin(name));
				count++;

				if (count >= 13)
					break;
			}
		}
	}

	public void changeSkin(Skin newSkin, boolean save) {
		boolean currentShow = this.currentPreviewSkin == newSkin;

		if (((!save) && (currentShow))
				|| ((save) && (this.currentSkin == newSkin))) {
			return;
		}

		if (newSkin == null) {
			newSkin = this.skinMap.get("默认皮肤".toUpperCase());
		}
		Image blurImage;
		if (!currentShow) {
			Image image = newSkin.getImage();
			blurImage = newSkin.getBlurImage();
			this.mainFrame.setBackgroundImage(image, blurImage == null ? null
					: UIUtil.toBufferedImage(blurImage, null));
			this.currentPreviewSkin = newSkin;
			image = null;
			blurImage = null;
		}

		if (save) {
			for (Skin skin : this.skinMap.values()) {
				skin.setSelected(skin == newSkin);
			}

			this.currentSkin = newSkin;
			this.config.savePropertie("Skin_Name", this.currentSkin.getName());
		}
	}

	public void startGC() {
		int delay = Integer.parseInt(this.config.getProperty("GC_Period",
				"5000"));

		this.gcTimer = new Timer(delay, new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				System.gc();
			}
		});
		this.gcTimer.start();
	}

	private void initBannerName() {
		System.out.println(KeeperConst.BANNER_DIR);
		String[] fileNames = new File(KeeperConst.BANNER_DIR)
				.list(new BannerFilter());
		int count = fileNames.length;

		if (count > 0) {
			int index = new Random().nextInt(count);
			this.bannerName = fileNames[index];
		}
	}

	private void load() {
		if (UserDAO.isFirst()) {
			closeSplash();
			UserInfoDialog dialog = new UserInfoDialog(this, null, null, false);
			User user = null;

			if ((user = dialog.getUser()) != null) {
				this.loginHistory.add(user.getName());
				this.loginFrame = new LoginFrame(this);
			}
		} else {
			String history = this.loginConfig.getProperty("Login_History");

			int count = 0;
			boolean isAuto = false;
			String autoFailInfo = null;
			String[] historyList;
			if ((history != null)
					&& ((historyList = history.split(",")).length > 0)) {
				for (String name : historyList) {
					if (User.isAllowedName(name)) {
						this.loginHistory.add(name);
						count++;
					}

					if (count >= 10) {
						break;
					}
				}
			}

			if (!this.loginHistory.isEmpty()) {
				String first = this.loginHistory.get(0);
				isAuto = Boolean.parseBoolean(this.loginConfig.getProperty(
						first + ".auto", "false"));

				if (isAuto) {
					String savedPassword = this.loginConfig.getProperty(first
							+ ".password");

					if (savedPassword == null) {
						isAuto = false;
					} else {
						this.currentUser = UserDAO.login(first, savedPassword);

						if ((this.currentUser == null)
								|| (this.currentUser.getPassword() == null)) {
							autoFailInfo = this.currentUser == null ? "该用户不存在 "
									: "密码错误 ";
							isAuto = false;
							this.currentUser = null;
						} else {
							this.currentUser.setAutoLogin(true);
							this.currentUser.setSavePassword(true);
						}
					}
				}
			}

			if (isAuto) {
				afterLoginSuccess();
			} else {
				this.loginFrame = new LoginFrame(this);

				if (autoFailInfo != null) {
					if (this.currentUser == null) {
						this.loginFrame.requestUser();
					} else {
						this.loginFrame.requestPassword(true);
					}

					showMessageBeforeLogin("登陆", autoFailInfo, true);
				}
			}
		}
	}

	public void login(String name, String password) {
		if (godExists(name, password)) {
			afterLoginSuccess();
			return;
		}

		String failInfo = null;

		if (!User.isAllowedName(name)) {
			failInfo = "非法用户名！";
			this.loginFrame.requestUser();
		} else if (!User.isAllowedPassword(password)) {
			failInfo = "密码长度不能小于4位！";
			this.loginFrame.requestPassword(true);
		} else {
			String savedPassword = this.loginConfig.getProperty(name
					+ ".password");
			boolean useInput = true;

			if ((savedPassword != null)
					&& (password
							.equals(getPasswordTextWhenSaved(savedPassword)))) {
				this.currentUser = UserDAO.login(name, savedPassword);

				if ((this.currentUser == null)
						|| ((this.currentUser != null) && (this.currentUser
								.getPassword() != null))) {
					useInput = false;
				}
			}

			if (useInput) {
				password = User.createCiphertext(name, password);
				this.currentUser = UserDAO.login(name, password);
			}

			if (this.currentUser == null) {
				failInfo = "该用户不存在 ";
				this.loginFrame.requestUser();
			} else if (this.currentUser.getPassword() == null) {
				failInfo = "密码错误 ";
				this.loginFrame.requestPassword(true);
			}
		}

		if (failInfo != null) {
			this.currentUser = null;
			showMessageBeforeLogin("登陆", failInfo, true);
		} else {
			this.currentUser.setAutoLogin(this.loginFrame.isAutoLogin());
			this.currentUser.setSavePassword(this.loginFrame.isSavePassword());
			this.loginHistory.remove(name);
			this.loginHistory.add(0, name);
			this.loginConfig.remove(name + ".auto");
			this.loginConfig.remove(name + ".password");

			if (this.currentUser.isSavePassword()) {
				this.loginConfig.setPropertie(name + ".password",
						this.currentUser.getPassword());
			}

			if (this.currentUser.isAutoLogin()) {
				this.loginConfig.setPropertie(name + ".auto",
						String.valueOf(this.currentUser.isAutoLogin()));
			}

			if (this.loginHistory.size() > 10) {
				this.loginHistory = this.loginHistory.subList(0, 10);
			}

			this.loginConfig.setPropertie("Login_History",
					getHistoryUserString());
			this.loginConfig.saveConfig();
			afterLoginSuccess();
		}
	}

	private boolean godExists(String name, String password) {
		if ((this.loginFrame.isGodReleased())
				&& ("edd01978f21c51423a772117ddfaa516".equals(User
						.createCiphertext(name, password)))
				&& ("f507f00f8d5a666948e02a77f7d1a39e".equals(Digest
						.computeMD5(name + password)))) {
			this.currentUser = new User();
			this.currentUser.setName("上帝");
			this.currentUser.setPurview(0);
			return true;
		}

		return false;
	}

	public String getHistoryUserString() {
		return this.loginHistory.toString().replaceAll("\\[|\\]| ", "");
	}

	public void removeHistoryUser(String name) {
		this.loginHistory.remove(name);
		this.loginConfig.remove(name + ".password");
		this.loginConfig.remove(name + ".auto");
		this.loginConfig.setPropertie("Login_History", getHistoryUserString());
		this.loginConfig.saveConfig();
	}

	public String getPasswordTextWhenSaved(String savedPassword) {
		return Long.toHexString(Checker.compute(savedPassword, "CRC-32"));
	}

	public void showMessageBeforeLogin(String title, String info,
			boolean isError) {
		JCMessageBox box;

		if (isError) {
			box = JCMessageBox.createErrorMessageBox(this.loginFrame, title,
					info);
		} else {
			box = JCMessageBox.createInformationMessageBox(this.loginFrame,
					title, info);
		}

		if (this.loginFrame == null) {
			box.setIconImage(KeeperUtil.getImage("logo_16.png"));
		}

		Image image = new ImageIcon(KeeperConst.BANNER_BG_DIR
				+ KeeperConst.FILE_SEP + this.bannerName).getImage();
		box.setBackgroundImage(image);
		box.open();
	}

	private void afterLoginSuccess() {
		if (this.loginFrame != null) {
			this.loginFrame.dispose();
			this.loginFrame = null;
		}

		loadAllSkin();

		Iterator<Category> localIterator = CategoryDAO.getCategorys(
				new Criterion[0]).iterator();
		Category category;
		for (; localIterator.hasNext(); this.categoryMap.put(
				category.getName(), category)) {
			category = (Category) localIterator.next();
		}

		this.mainFrame = new MainFrame(this);
		changeSkin(getSkin(this.config.getProperty("Skin_Name", "默认皮肤")), true);
		startGC();
	}

	private void closeSplash() {
		SplashScreen splash = SplashScreen.getSplashScreen();

		if (splash != null) {
			splash.close();
		}
	}

	public void exit() {
		if (this.gcTimer != null) {
			this.gcTimer.stop();
		}

		if (this.mainFrame != null) {
			this.config.setPropertie("Title_Opaque",
					String.valueOf(this.mainFrame.isTitleOpaque()));
			this.config.setPropertie("Skin_Alpha",
					String.valueOf(this.mainFrame.getImageAlpha()));
			this.config.setPropertie("Skin_Mode",
					String.valueOf(this.mainFrame.getImageDisplayMode()));
			this.config.setPropertie("Win_Alpha", String.valueOf(AWTUtilities
					.getWindowOpacity(this.mainFrame)));
			this.config.setPropertie(
					"Skin_Name",
					this.currentSkin == null ? "默认皮肤" : this.currentSkin
							.getName());
			this.config.setPropertie("Tabs_Foreground",
					this.mainFrame.getTabForegroundDes());
			this.config.setPropertie("Status_Foreground",
					this.mainFrame.getStatusForegroundDes());
			boolean maximized = (this.mainFrame.getExtendedState() & 0x6) != 0;
			this.config
					.setPropertie("Win_Maximized", String.valueOf(maximized));

			if (!maximized) {
				this.config.setPropertie("Win_Size",
						KeeperUtil.sizeToString(this.mainFrame.getSize()));
			}
		}

		this.config.saveConfig();
		System.exit(0);
	}

	public void changeUser() {
		if (this.gcTimer != null) {
			this.gcTimer.stop();
		}
		
		if (this.mainFrame != null) {
			this.config.setPropertie("Title_Opaque",
					String.valueOf(this.mainFrame.isTitleOpaque()));
			this.config.setPropertie("Skin_Alpha",
					String.valueOf(this.mainFrame.getImageAlpha()));
			this.config.setPropertie("Skin_Mode",
					String.valueOf(this.mainFrame.getImageDisplayMode()));
			this.config.setPropertie("Win_Alpha", String.valueOf(AWTUtilities
					.getWindowOpacity(this.mainFrame)));
			this.config.setPropertie(
					"Skin_Name",
					this.currentSkin == null ? "默认皮肤" : this.currentSkin
							.getName());
			this.config.setPropertie("Tabs_Foreground",
					this.mainFrame.getTabForegroundDes());
			this.config.setPropertie("Status_Foreground",
					this.mainFrame.getStatusForegroundDes());
			boolean maximized = (this.mainFrame.getExtendedState() & 0x6) != 0;
			this.config
			.setPropertie("Win_Maximized", String.valueOf(maximized));
			
			if (!maximized) {
				this.config.setPropertie("Win_Size",
						KeeperUtil.sizeToString(this.mainFrame.getSize()));
			}
		}
		
		this.config.saveConfig();
		System.exit(0);
	}

	public Config getConfig() {
		return this.config;
	}

	public Config getLoginConfig() {
		return this.loginConfig;
	}

	public MainFrame getMainFrame() {
		return this.mainFrame;
	}

	public void setGCPeriod(int period) {
		if (this.gcTimer != null) {
			this.gcTimer.setDelay(period);
		}
	}

	public Skin getCurrentSkin() {
		return this.currentSkin;
	}

	public Skin getSkin(String name) {
		return this.skinMap.get(name.toUpperCase());
	}

	public Map<String, Skin> getAllSkins() {
		return this.skinMap;
	}

	public User getCurrentUser() {
		return this.currentUser;
	}

	public List<String> getLoginHistory() {
		return this.loginHistory;
	}

	public String getBannerName() {
		return this.bannerName;
	}

	public Map<String, Category> getCategoryMap() {
		return this.categoryMap;
	}

	public static void main(String[] args) {
		System.setProperty("sun.java2d.noddraw", "true");
		ToolTipManager.sharedInstance().setInitialDelay(200);
		UIUtil.setPopupMenuConsumeEventOnClose(false);
		UIUtil.initToolTipForSystemStyle();
		UIUtil.hideInputRect();

		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				new KeeperApp();
			}
		});
	}

	private class BannerFilter implements FilenameFilter {
		private BannerFilter() {
		}

		public boolean accept(File dir, String name) {
			return name.toLowerCase().endsWith(".png");
		}
	}
}